/**
 * 对promise进行校验
 * 校验是否符合a+规范
 * npm install -g promises-aplus-tests
 * 在这个文件夹下面运行
 * promises-aplus-tests promise.js
 * 进行校验的js文件下cd
 * module.exports = Promise;
 */

const Pending = "pending";
const Fulfilled = "fulfilled";
const Rejected = "rejected";

function Promise(executor) {
  var _this = this;
  // 当前状态
  _this.status = Pending;
  // 成功结果
  _this.value = undefined;
  // 失败原因
  _this.reason = undefined;
  /**
   * 那么如何让我们的Promise来支持异步呢？
   * 我们可以参考发布订阅模式，
   * 在执行then方法的时候，
   * 如果当前还是Pending状态，
   * 就把回调函数寄存到一个数组中，
   * 当状态发生改变时，去数组中取出回调函数；
   */
  _this.onFulfilled = [];
  _this.onRejected = [];
  // 成功回调函数
  function resolve(value) {
    // 如果状态是pending，则可改变状态
    if (_this.status === Pending) {
      _this.status = Fulfilled;
      _this.value = value;
      // 如果有回调函数，则执行回调函数
      _this.onFulfilled.forEach((fn) => fn(value));
    }
  }
  // 失败回调函数
  function reject(reason) {
    // 如果状态是pending，则可改变状态
    if (_this.status === Pending) {
      _this.status = Rejected;
      _this.reason = reason;
      // 如果有回调函数，则执行回调函数
      _this.onRejected.forEach((fn) => fn(reason));
    }
  }
  // 但是executor也会可能存在异常，因此通过try/catch来捕获一下异常情况
  try {
    // 执行回调函数
    executor(resolve, reject);
  } catch (err) {
    reject(err);
  }
}

/**
 * Promise的then实现
 * 在规范中也说了，onFulfilled和onRejected是可选的，
 * 因此我们对两个值进行一下类型的判断：
 * onFulfilled 和 onRejected 都是可选参数。
 * 如果 onFulfilled 不是函数，其必须被忽略。
 * 如果 onRejected 不是函数，其必须被忽略
 */
Promise.prototype.then = function (onFulfilled, onRejected) {
  // // 如果状态是fulfilled
  // if (this.status === Fulfilled) {
  //   // 判断onFulfilled是否是函数
  //   typeof onFulfilled === "function" && onFulfilled(this.value);
  // }
  // // 如果状态是rejected
  // if (this.status === Rejected) {
  //   // 判断onRejected是否是函数
  //   typeof onRejected === "function" && onRejected(this.reason);
  // }
  // // 如果状态是pending
  // if (this.status === Pending) {
  //   // 将回调函数存入数组
  //   typeof onFulfilled === "function" && this.onFulfilled.push(onFulfilled);
  //   typeof onRejected === "function" && this.onRejected.push(onRejected);
  // }

  /**
   * 这里不管onFulfilled和onRejected传什么值，
   * 只要不是函数，就继续向下传入，
   * 直到有函数进行接收；因此我们对then方法进行如下完善：
   */
  // _this是promise1的实例对象
  let _this = this;
  // 如果onFulfilled是函数,则执行函数
  onFulfilled =
    typeof onFulfilled === "function" ? onFulfilled : (value) => value;
  // 如果onRejected是函数,则执行函数
  onRejected =
    typeof onRejected === "function"
      ? onRejected
      : (reason) => {
          throw reason;
        };

  // promise的链式调用
  let promise2 = new Promise((resolve, reject) => {
    /**
     * 由于then的回调是异步执行的，
     * 因此我们需要把onFulfilled和onRejected执行放到异步中去执行，
     * 同时做一下错误的处理：
     *
     * 如果状态是fulfilled
     */
    if (_this.status === Fulfilled) {
      setTimeout(() => {
        try {
          let x = onFulfilled(_this.value);
          resolvePromise(promise2, x, resolve, reject);
        } catch (err) {
          reject(err);
        }
      });
    } else if (_this.status === Rejected) {
      setTimeout(() => {
        try {
          let x = onRejected(_this.reason);
          resolvePromise(promise2, x, resolve, reject);
        } catch (err) {
          reject(err);
        }
      });
    } else if (_this.status === Pending) {
      _this.onFulfilled.push(() => {
        setTimeout(() => {
          try {
            let x = onFulfilled(_this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (err) {
            reject(err);
          }
        });
      });
      _this.onRejected.push(() => {
        setTimeout(() => {
          try {
            let x = onRejected(_this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (err) {
            reject(err);
          }
        });
      });
    }
  });
  return promise2;
};

//promise2：新的Promise对象
//x：上一个then的返回值
//resolve：promise2的resolve
//reject：promise2的reject
function resolvePromise(promise2, x, resolve, reject) {}

let p = new Promise((resolve, reject) => {
  console.log("执行了");
  setTimeout(() => {
    resolve("结果是");
  }, 1000);
});
p.then(
  (res) => {
    console.log(res, "->成功了");
  },
  (err) => {
    console.log(err, "->出错了");
  }
).then((res) => {
  console.log(res, "->成功了12");
});

// 暴露模块
module.exports = Promise;
